package bancosys.tec.persist.hibernate.eventListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.FlushMode;
import org.hibernate.event.AutoFlushEvent;
import org.hibernate.event.AutoFlushEventListener;
import org.hibernate.event.EventSource;
import org.hibernate.event.def.DefaultAutoFlushEventListener;

/**
 * Defines the default flush event listeners used by hibernate for flushing session state in response to generated auto-flush events.
 * 
 * @author Cesar Olmos
 */
public class DirtyAwareAutoFlushEventListener extends AbstractDirtyAwareFlushEventListener implements AutoFlushEventListener {

    private static final Log LOGGER = LogFactory.getLog(DefaultAutoFlushEventListener.class);

    /**
     * Handle the given auto-flush event.
     * 
     * @param event The auto-flush event to be handled.
     */
    public void onAutoFlush(AutoFlushEvent event) {

        final EventSource source = event.getSession();

        if (this.flushMightBeNeeded(source)) {

            final int oldSize = source.getActionQueue().numberOfCollectionRemovals();

            this.flushEverythingToExecutions(event);

            if (this.flushIsReallyNeeded(event, source)) {

                LOGGER.trace("Need to execute flush");

                this.performExecutions(source);
                this.postFlush(source);
                // note: performExecutions() clears all collectionXxxxtion
                // collections (the collection actions) in the session

                if (source.getFactory().getStatistics().isStatisticsEnabled()) {
                    source.getFactory().getStatisticsImplementor().flush();
                }

            } else {
                LOGGER.trace("Dont need to execute flush");
                source.getActionQueue().clearFromFlushNeededCheck(oldSize);
            }

            event.setFlushRequired(this.flushIsReallyNeeded(event, source));

        }

    }

    /**
     * @param event the event
     * @param source the event source
     * @return boolean
     */
    private boolean flushIsReallyNeeded(AutoFlushEvent event, final EventSource source) {
        return source.getActionQueue().areTablesToBeUpdated(event.getQuerySpaces()) || source.getFlushMode() == FlushMode.ALWAYS;
    }

    /**
     * @param source {@link EventSource}
     * @return boolean
     */
    private boolean flushMightBeNeeded(final EventSource source) {
        return !source.getFlushMode().lessThan(FlushMode.AUTO) && source.getDontFlushFromFind() == 0
                && source.getPersistenceContext().hasNonReadOnlyEntities();
    }
}
